package cn.virens.common.boot.dubbo.consumer.autoconfig;

import cn.virens.common.boot.dubbo.consumer.converter.*;
import cn.virens.common.boot.filter.exception.SimpleHandlerExceptionCustomizer;
import cn.virens.common.boot.filter.exception.SimpleHandlerExceptionFilter;
import cn.virens.common.oauth.exception.AuthPermException;
import cn.virens.common.oauth.exception.AuthRoleException;
import cn.virens.common.oauth.exception.NoLoginException;
import cn.virens.common.util.exception.APIException;
import cn.virens.common.util.fastjson.FastJsonConfigExtend;
import com.alibaba.fastjson2.support.spring6.http.converter.FastJsonHttpMessageConverter;
import com.alibaba.fastjson2.support.spring6.webservlet.view.FastJsonJsonView;
import org.beetl.ext.spring6.EnableBeetl;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.StandardCharsets;
import java.util.List;

@EnableBeetl
@Configuration
public class SpringServletWebAutoConfig implements SimpleHandlerExceptionCustomizer, WebMvcConfigurer {

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) throws APIException {
        resolvers.add(new SimpleHandlerExceptionFilter.EmptyExceptionResolver());
    }

    /**
     * 内容协商器配置。将后缀为json的配置为json处理，后缀为jspx的为页面处理
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) throws APIException {
        configurer.mediaType("json", MediaType.APPLICATION_JSON);
        configurer.mediaType("jspx", MediaType.TEXT_HTML);
    }

    /**
     * 添加消息转换器
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) throws APIException {
        var jsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        jsonHttpMessageConverter.setFastJsonConfig(FastJsonConfigExtend.INSTANCE);
        jsonHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8);
        jsonHttpMessageConverter.setSupportedMediaTypes(List.of(//
                MediaType.APPLICATION_JSON_UTF8,//
                MediaType.APPLICATION_JSON//
        ));

        // 将消息转换器转给Spring进行管理
        converters.addFirst(jsonHttpMessageConverter);
    }

    /**
     * 添加视图解析器
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) throws APIException {
        // 配置FastJson 视图
        FastJsonJsonView fastJsonJsonView = new FastJsonJsonView();
        fastJsonJsonView.setFastJsonConfig(FastJsonConfigExtend.INSTANCE);

        // 注册视图
        registry.enableContentNegotiation(fastJsonJsonView);
    }

    @Override
    public void customize(SimpleHandlerExceptionFilter filter) throws APIException {
        filter.addExceptionMessage(DataIntegrityViolationException.class, "请检查约束");
        filter.addExceptionMessage(BadSqlGrammarException.class, "SQL出错");
        filter.addExceptionMessage(AuthPermException.class, "未授权:权限");
        filter.addExceptionMessage(AuthRoleException.class, "未授权:角色");
        filter.addExceptionMessage(NoLoginException.class, "未登录");
    }

    /**
     * 格式转换器
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new LocalDateTimeConverter());
        registry.addConverter(new BigDecimalConverter());
        registry.addConverter(new LocalDateConverter());
        registry.addConverter(new LocalTimeConverter());
        registry.addConverter(new IntegerConverter());
        registry.addConverter(new BoolConverter());
        registry.addConverter(new LongConverter());
        registry.addConverter(new DateConverter());
    }
}
